/**
 * @file HandlerRegister.cpp
 * @author Derek Liu (yjkhtddx@sina.com)
 * @brief 注册事件处理器
 * @version 0.0.1
 * @date 2020-07-17
 * 
 * @coryright Copyright Sci-Tech Laboratories (c) 2020
 * 
 */

#include "HandlerRegister.hpp"
#include "STL_Log.hpp"
#include "DBMgr.hpp"
#include <eXosip2/eX_setup.h>
#include <sstream> // std::stringstream, std::stringbuf

#define AUTH_TYPE "Digest"
#define ALGORITHTHM "MD5"
#define QOP "\"auth\""
#define REALM "\"yjkhtddx\""
#define NONCE "\"8c460324b01e6a7388af5b236994c539\""

HandlerRegister::HandlerRegister() {}
// HandlerRegister::~HandlerRegister() {}

int HandlerRegister::sendWWWAuthenticateResponse(const char *uname, struct eXosip_t *excontext, int tid, int status)
{
    osip_www_authenticate_t *www_auth_test;

    int result = OSIP_SUCCESS;
    osip_message_t *answer = nullptr;

    eXosip_lock(excontext);
    result = eXosip_message_build_answer(excontext, tid, status, &answer);

    if (OSIP_SUCCESS == result)
    {
        int method = 2;

        if (method == 1)
        {
            // 方法一:
            osip_www_authenticate_t *www_auth;
            osip_www_authenticate_init(&www_auth);
            www_auth_test = www_auth;
            osip_www_authenticate_set_auth_type(www_auth, osip_strdup(AUTH_TYPE));
            // osip_www_authenticate_set_algorithm_MD5(www_auth);
            osip_www_authenticate_set_realm(www_auth, osip_strdup(REALM));
            osip_www_authenticate_set_qop_options(www_auth, osip_strdup(QOP));
            osip_www_authenticate_set_nonce(www_auth, osip_strdup(NONCE));
            osip_list_add(&answer->www_authenticates, www_auth, -1);
            osip_free(www_auth);

            // osip_www_authenticate_free(www_auth);//错误用法，内存释放过早，发出数的数据不对 //据说eXosip_execute定时释放，先不使用此方法能够
        }

        if (method == 2)
        {
            // 方法二:
            osip_www_authenticate_t *www_auth;
            osip_www_authenticate_init(&www_auth);
            osip_www_authenticate_set_auth_type(www_auth, osip_strdup(AUTH_TYPE));
            // osip_www_authenticate_set_algorithm_MD5(www_auth);
            osip_www_authenticate_set_realm(www_auth, osip_strdup(REALM));
            osip_www_authenticate_set_qop_options(www_auth, osip_strdup(QOP));
            osip_www_authenticate_set_nonce(www_auth, osip_strdup(NONCE));

            char *str_www_auth = NULL;
            osip_www_authenticate_to_str(www_auth, &str_www_auth);
            osip_message_set_www_authenticate(answer, str_www_auth);
            // osip_message_set_header(answer, "WWW-Authenticate", str_www_auth); // 应该等同

            /* 注意释放空间 */
            osip_free(str_www_auth);
            osip_www_authenticate_free(www_auth);
            www_auth = nullptr;
        }

        result = eXosip_message_send_answer(excontext, tid, status, answer);
    }
    else
    {
        result = eXosip_message_send_answer(excontext, tid, status, nullptr);
    }

    eXosip_unlock(excontext);

    stl::log("sendWWWAuthenticateResponse: %d to uname:%s, result: %d", status, uname, result);

    return result;
}

int HandlerRegister::HandleRegisterRequest(const sip_event_sptr &e)
{
    const char *username = e->exevent->request->from->url->username;
    const char *host = e->exevent->request->from->url->host;
    uint16_t port = std::stoul(std::string(e->exevent->request->from->url->port));

    //鉴权信息
    osip_authorization_t *authentication = nullptr;
    {
        osip_message_get_authorization(e->exevent->request, 0, &authentication);
        if (nullptr == authentication)
        {
            sendWWWAuthenticateResponse(username, e->excontext, e->exevent->tid, SIP_UNAUTHORIZED);
            return 0;
        }
        // std::string username = std::string(authentication->username);
        // std::string algorithm = std::string(authentication->algorithm);
        // std::string realm = std::string(authentication->realm);
        // std::string nonce = std::string(authentication->nonce);
        // std::string response = std::string(authentication->response);
        // std::string uri = std::string(authentication->uri);
        // TODO digist 摘要认证
        bool isAuth = true;
        if (isAuth)
        {
            sendSimplyResp(username, e->excontext, e->exevent->tid, SIP_OK);
            DBMgr::Device device;
            device.username = std::string(username);
            device.host = std::string(host);
            device.port = port;
            int deviceId = DBMgr::instance()->addDevice(device);
            
            static bool once = false;//TODO 去除重复任务
            if(!once){
                once = true;
                DBMgr::instance()->addTask(deviceId);
            }
        }
        else
        {
            sendWWWAuthenticateResponse(username, e->excontext, e->exevent->tid, SIP_UNAUTHORIZED);
        }
    }
    authentication = nullptr;
    return 0;
}